#include "TimerManager.h"
#include <chrono>

namespace SeanNetwork {

TimerManager::TimerManager(asio::io_context& ioContext)
    : m_IoContext(ioContext),
      m_Strand(asio::make_strand(ioContext)),
      m_NextTimerId(1) {
}

TimerManager::~TimerManager() {
    // Stop all timers
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    for (auto& [timerId, timerData] : m_Timers) {
        if (timerData.Timer) {
            asio::error_code ec;
            timerData.Timer->cancel(ec);
        }
    }
    
    m_Timers.clear();
}

uint32_t TimerManager::CreateTimer(
    const TimerConfig& config,
    TimerCallback callback,
    const std::string& name) {
    
    if (!callback) {
        return 0; // Invalid callback
    }
    
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    // Generate new timer ID
    uint32_t timerId = m_NextTimerId++;
    
    // Create timer data
    TimerData& timerData = m_Timers[timerId];
    timerData.Id = timerId;
    timerData.Config = config;
    timerData.Callback = callback;
    timerData.Timer = std::make_shared<asio::steady_timer>(m_IoContext);
    timerData.Active = false;
    timerData.Name = name;
    
    return timerId;
}

bool TimerManager::StartTimer(uint32_t timerId) {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    auto it = m_Timers.find(timerId);
    if (it == m_Timers.end() || !it->second.Timer) {
        return false;
    }
    
    TimerData& timerData = it->second;
    
    // Cancel any existing operation
    asio::error_code ec;
    timerData.Timer->cancel(ec);
    
    // Set expiry time
    timerData.Timer->expires_after(
        std::chrono::milliseconds(timerData.Config.InitialDelayMs));
    
    // Start the timer
    auto timer = timerData.Timer;
    uint32_t id = timerId;
    
    timerData.Timer->async_wait(
        asio::bind_executor(m_Strand, 
            [this, id, timer](const asio::error_code& ec) {
                HandleTimerExpired(id, ec);
            }));
    
    timerData.Active = true;
    return true;
}

bool TimerManager::StopTimer(uint32_t timerId) {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    auto it = m_Timers.find(timerId);
    if (it == m_Timers.end() || !it->second.Timer) {
        return false;
    }
    
    // Cancel the timer
    asio::error_code ec;
    it->second.Timer->cancel(ec);
    it->second.Active = false;
    
    return true;
}

bool TimerManager::RestartTimer(uint32_t timerId) {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    auto it = m_Timers.find(timerId);
    if (it == m_Timers.end() || !it->second.Timer) {
        return false;
    }
    
    TimerData& timerData = it->second;
    
    // Cancel any existing operation
    asio::error_code ec;
    timerData.Timer->cancel(ec);
    
    // Set expiry time
    timerData.Timer->expires_after(
        std::chrono::milliseconds(timerData.Config.InitialDelayMs));
    
    // Start the timer
    auto timer = timerData.Timer;
    uint32_t id = timerId;
    
    timerData.Timer->async_wait(
        asio::bind_executor(m_Strand, 
            [this, id, timer](const asio::error_code& ec) {
                HandleTimerExpired(id, ec);
            }));
    
    timerData.Active = true;
    return true;
}

bool TimerManager::DestroyTimer(uint32_t timerId) {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    auto it = m_Timers.find(timerId);
    if (it == m_Timers.end()) {
        return false;
    }
    
    // Cancel the timer if it's active
    if (it->second.Timer) {
        asio::error_code ec;
        it->second.Timer->cancel(ec);
    }
    
    // Remove the timer
    m_Timers.erase(it);
    return true;
}

bool TimerManager::UpdateTimer(uint32_t timerId, const TimerConfig& config) {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    auto it = m_Timers.find(timerId);
    if (it == m_Timers.end()) {
        return false;
    }
    
    bool wasActive = it->second.Active;
    
    // Update configuration
    it->second.Config = config;
    
    // Restart if it was active
    if (wasActive) {
        // Cancel any existing operation
        asio::error_code ec;
        it->second.Timer->cancel(ec);
        
        // Set expiry time
        it->second.Timer->expires_after(
            std::chrono::milliseconds(config.InitialDelayMs));
        
        // Start the timer
        auto timer = it->second.Timer;
        uint32_t id = timerId;
        
        it->second.Timer->async_wait(
            asio::bind_executor(m_Strand, 
                [this, id, timer](const asio::error_code& ec) {
                    HandleTimerExpired(id, ec);
                }));
        
        it->second.Active = true;
    }
    
    return true;
}

bool TimerManager::IsTimerActive(uint32_t timerId) const {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    auto it = m_Timers.find(timerId);
    return (it != m_Timers.end() && it->second.Active);
}

bool TimerManager::GetTimerConfig(uint32_t timerId, TimerConfig& config) const {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    auto it = m_Timers.find(timerId);
    if (it == m_Timers.end()) {
        return false;
    }
    
    config = it->second.Config;
    return true;
}

std::string TimerManager::GetTimerName(uint32_t timerId) const {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    auto it = m_Timers.find(timerId);
    if (it == m_Timers.end()) {
        return "";
    }
    
    return it->second.Name;
}

void TimerManager::HandleTimerExpired(uint32_t timerId, const asio::error_code& error) {
    // Skip if cancelled
    if (error == asio::error::operation_aborted) {
        return;
    }
    
    TimerData timerData;
    bool shouldReschedule = false;
    
    // Get timer data
    {
        std::lock_guard<std::mutex> lock(m_TimersMutex);
        
        auto it = m_Timers.find(timerId);
        if (it == m_Timers.end()) {
            return;
        }
        
        timerData = it->second;
        
        // Mark timer as inactive if it's a one-shot timer or if we're not auto-resetting
        if (!timerData.Config.AutoReset || timerData.Config.IntervalMs == 0) {
            it->second.Active = false;
        } else {
            shouldReschedule = true;
        }
    }
    
    // Call the timer callback outside the lock
    if (timerData.Callback) {
        timerData.Callback(timerId);
    }
    
    // Reschedule if needed
    if (shouldReschedule) {
        std::lock_guard<std::mutex> lock(m_TimersMutex);
        
        auto it = m_Timers.find(timerId);
        if (it != m_Timers.end() && it->second.Active && it->second.Timer) {
            // Set expiry time for next interval
            it->second.Timer->expires_after(
                std::chrono::milliseconds(it->second.Config.IntervalMs));
            
            // Start the timer
            auto timer = it->second.Timer;
            uint32_t id = timerId;
            
            it->second.Timer->async_wait(
                asio::bind_executor(m_Strand, 
                    [this, id, timer](const asio::error_code& ec) {
                        HandleTimerExpired(id, ec);
                    }));
        }
    }
}

uint32_t TimerManager::AddTimer(
    uint32_t delayMs,
    std::function<void()> callback,
    TimerType timerType,
    const std::string& name) {
    
    TimerConfig config;
    config.InitialDelayMs = delayMs;
    
    if (timerType == TimerType::Repeated) {
        config.IntervalMs = delayMs;
        config.AutoReset = true;
    } else {
        config.IntervalMs = 0;
        config.AutoReset = false;
    }
    
    // 包装回调函数，将原始无参数回调转换为接受timerId参数的回调
    return CreateTimer(config, [callback](uint32_t) { callback(); }, name);
}

bool TimerManager::CancelTimer(uint32_t timerId) {
    return StopTimer(timerId);
}

void TimerManager::ClearAllTimers() {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    for (auto& [timerId, timerData] : m_Timers) {
        if (timerData.Timer) {
            asio::error_code ec;
            timerData.Timer->cancel(ec);
        }
    }
    
    m_Timers.clear();
}

void TimerManager::Update(float deltaTime) {
    std::lock_guard<std::mutex> lock(m_TimersMutex);
    
    // 检查所有定时器，更新和触发定时器
    std::vector<uint32_t> expiredTimers;
    
    for (auto& pair : m_Timers) {
        auto& timerData = pair.second;
        if (!timerData.Active) continue;
        
        // 这里只处理那些需要手动更新的定时器
        // 使用 asio 自动调度的定时器不在这里处理
        if (timerData.Timer && timerData.Timer->expiry() <= asio::steady_timer::clock_type::now()) {
            expiredTimers.push_back(pair.first);
        }
    }
    
    // 执行过期的定时器回调
    for (uint32_t timerId : expiredTimers) {
        auto it = m_Timers.find(timerId);
        if (it != m_Timers.end() && it->second.Active) {
            auto callback = it->second.Callback;
            auto timerPtr = it->second.Timer;
            
            // 如果不是自动重置的定时器，标记为非活动
            if (!it->second.Config.AutoReset) {
                it->second.Active = false;
            } else {
                // 重新设置定时器
                timerPtr->expires_after(
                    std::chrono::milliseconds(it->second.Config.IntervalMs));
                
                // 重新启动定时器
                auto id = timerId;
                timerPtr->async_wait(
                    asio::bind_executor(m_Strand,
                        [this, id, timerPtr](const asio::error_code& ec) {
                            HandleTimerExpired(id, ec);
                        }));
            }
            
            // 释放锁后执行回调，避免死锁
            m_TimersMutex.unlock();
            try {
                if (callback) {
                    callback(timerId);
                }
            } catch (...) {
                // 捕获所有异常，保证定时器管理器继续运行
                m_TimersMutex.lock();
                continue;
            }
            m_TimersMutex.lock();
        }
    }
}

} // namespace SeanNetwork
